package com.hsw.bledemo.review.kotlin

import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty

/**
 * @author: HSW
 * @data: 2024/7/4
 * @desc: by 委托
 */

/**
 * 接口委托（相当于Java中的代理模式）
 * 优势：把类实现接口需要重写的方法，部分或完全委托给一个成员对象来实现，可以让该实现类不用关心接口核心功能的具体实现而是额外的功能定制和扩展。
 */

interface Proxy {
    fun show()
}

class ProxyImpl: Proxy {
    override fun show() {
        println("show things")
    }
}

// 不使用委托实现 代理模式 和 装饰器模式
class ProxyNormal(val proxy: Proxy): Proxy {
    // 代理模式的实现
    override fun show() {
        proxy.show()
    }

    // 装饰器模式拓展功能
    fun doSomethings() {
        println("other things")
    }
}

// 使用 by 委托的方式默认已经实现代理模式。
class Things(val proxy: Proxy) : Proxy by proxy {
    // 代理方面的代码已经不用写了，减少了模版代码

    // 装饰器模式拓展功能，还是需要自己写
    fun doSomethings() {
        println("other things")
    }
}

/**
 * 属性委托
 * 将属性的访问器委托给另一个对象，以减少模板代码并隐藏访问细节。
 */

class Phone {
    val number: Int = 1234

    val newNumber: Int by ScreenFactory()
}

// 把 Phone 属性的访问权发放到 ScreenFactory，这个对象就可以操作里面的属性
class ScreenFactory: ReadOnlyProperty<Phone, Int> {

    override fun getValue(thisRef: Phone, property: KProperty<*>): Int {
        /// 获取属性并操作
        return thisRef.number + 10
    }
}


/**
 * by lazy() 目的是只初始化一次
 * by 是关键字，lazy() 是高阶函数，实现了委托机制
 * LazyThreadSafetyMode.SYNCHRONIZED - 因为加了同步锁，只允许单个线程初始化
 * LazyThreadSafetyMode.PUBLICATION - 增加了原子判断，允许多个线程初始化，以最先初始化成功的值为最终值
 * LazyThreadSafetyMode.NONE - 非线程安全，如果多个线程同时初始化，可能会得到不同的值
 */

val name: String by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
    ""
}

/**
 * map 委托
 *
 * - 定义的属性名要和map的key保持一致
 * - val 可以委托给map和mutable ，var 只能委托给mutable
 */

class People(map: MutableMap<String, Any>) {
    val id: Int by map
    val name: String by map
}


fun main() {
    val things = Things(ProxyImpl())
    things.show()
    things.doSomethings()

    val phone = Phone()
    println(phone.newNumber)

    val map = mutableMapOf<String, Any>("id" to 123, "name" to "hsw")
    val people = People(map)
    println("id-${people.id}, name-${people.name}")
}